package cn.sylinx.hbatis.ext.mirage;

import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;

import cn.sylinx.hbatis.db.common.DbOper;
import cn.sylinx.hbatis.db.common.DefaultHbatisService;
import cn.sylinx.hbatis.db.common.Record;
import cn.sylinx.hbatis.db.mapper.ModelBuilder;
import cn.sylinx.hbatis.db.mapper.QueryMapper;
import cn.sylinx.hbatis.ext.parse.SqlParser;
import cn.sylinx.hbatis.ext.res.ClasspathSqlResource;
import cn.sylinx.hbatis.kit.Tuple;
import cn.sylinx.hbatis.plugin.datasource.JdbcResourcePlugin;

/**
 * MirageService, 读取类路径下的sql文件
 * 
 * @author han
 *
 */
public class DefaultMirageService extends DefaultHbatisService implements MirageService {

	/**
	 * 数据源名称
	 */
	private String datasourceName;

	/**
	 * 缓存支持
	 */
	private final MirageCacheQuery mirageCacheQuery;

	/**
	 * 多数据源 MirageService缓存
	 */
	private final Map<String, MirageService> dbServiceMap = new WeakHashMap<String, MirageService>();

	public DefaultMirageService() {
		this(JdbcResourcePlugin.DEFAULT_JDBC_RESOURCE_NAME);
	}

	public DefaultMirageService(String datasourceName) {

		super(datasourceName);
		this.datasourceName = datasourceName;
		this.mirageCacheQuery = createMirageCacheQuery();
		dbServiceMap.put(datasourceName, this);

	}

	@Override
	public MirageCacheQuery withMirageCache() {
		if (getCacheQuery() == null || mirageCacheQuery == null) {
			throw new UnsupportedOperationException("不支持缓存查询");
		}

		return mirageCacheQuery;
	}

	/**
	 * 创建缓存查询对象
	 * 
	 * @param params
	 * @return
	 */
	private MirageCacheQuery createMirageCacheQuery(Object... params) {
		return new DefaultMirageCacheQuery(getCacheQuery());
	}

	@Override
	public DbOper getDbOper() {
		return this;
	}

	public MirageService useService(String datasourceName) {

		MirageService dbService = dbServiceMap.get(datasourceName);
		if (dbService == null) {

			synchronized (datasourceName.intern()) {
				createInstanceInner(datasourceName);
			}

			dbService = dbServiceMap.get(datasourceName);
		}

		return dbService;

	}

	private void createInstanceInner(String datasourceName) {

		MirageService dbService = dbServiceMap.get(datasourceName);
		if (dbService == null) {
			dbService = createInstance(datasourceName);
			dbServiceMap.put(datasourceName, dbService);
		}
	}

	/**
	 * 创建一个MirageService
	 * 
	 * @param datasourceName
	 * @return
	 */
	protected MirageService createInstance(String datasourceName) {
		return new DefaultMirageService(datasourceName);
	}

	@Override
	public <T> List<T> query(ClasspathSqlResource sqlResource, Map<String, Object> params, Class<T> clz) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);
		QueryMapper<T> mapper = ModelBuilder.buildQueryMapper(clz);
		return useService(datasourceName).query(st, mapper, pms);
	}

	@Override
	public <T> List<T> queryObjectList(ClasspathSqlResource sqlResource, Map<String, Object> params, Class<T> clz) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);
		return useService(datasourceName).queryObject(st, clz, pms);
	}

	@Override
	public <T> T queryFirstObject(ClasspathSqlResource sqlResource, Map<String, Object> params, Class<T> clz) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);
		return useService(datasourceName).queryFirstObject(st, clz, pms);
	}

	@Override
	public List<Map<String, Object>> queryForMapList(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).queryMap(st, pms);
	}

	@Override
	public List<Record> queryForRecords(ClasspathSqlResource sqlResource, Map<String, Object> params) {
		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).queryRecords(st, pms);
	}

	@Override
	public Record queryFirstRecord(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).queryFirstRecord(st, pms);
	}

	@Override
	public List<Object[]> queryObjectArrayList(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).query(st, pms);
	}

	@Override
	public Object[] queryFirstObjectArray(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).queryFirst(st, pms);
	}

	@Override
	public Map<String, Object> queryFirstForMap(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).queryFirstMap(st, pms);
	}

	@Override
	public <T> T queryFirst(ClasspathSqlResource sqlResource, Map<String, Object> params, Class<T> clz) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);
		QueryMapper<T> mapper = ModelBuilder.buildQueryMapper(clz);
		return useService(datasourceName).queryFirst(st, mapper, pms);
	}

	@Override
	public int update(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).update(st, pms);
	}

	@Override
	public boolean execute(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).execute(st, pms);
	}

	@Override
	public int delete(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).update(st, pms);
	}

	@Override
	public Object save(ClasspathSqlResource sqlResource, Map<String, Object> params) {

		Tuple tp = SqlParser.parseSql(sqlResource, params);
		String st = (String) tp.get(0);
		Object[] pms = (Object[]) tp.get(1);

		return useService(datasourceName).save(st, pms);
	}

}
